﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OutLook.Model.Infrastructure;

namespace OutLook.Properties.Calc
{
    public class MetallSystem
    {

        #region Constructors

        public MetallSystem(List<Coupla> metallsystem)
        {
            metallcollection = new List<MetallSystemElement>();
            double SumPortion = 0;
            double Sum = 0;

            foreach (Coupla item in metallsystem)
            {
                Element metallElement = ElementsData.GetElement(item.Indicator);

                SumPortion = SumPortion + item.Value;
            }

            foreach (Coupla item in metallsystem)
            {
                Element metallElement = ElementsData.GetElement(item.Indicator);
                MetallSystemElement metallSystemElement = new MetallSystemElement();
                metallSystemElement.Name = item.Indicator;
                metallSystemElement.Percent = item.Value;
                metallSystemElement.PortialPercent = (item.Value / SumPortion) * 100;
                metallSystemElement.Mass = metallElement.Mass;
                metallSystemElement.Ru0 = metallElement.Ru0;
                metallSystemElement.TgAlfa = metallElement.TgAlfa;
                metallcollection.Add(metallSystemElement);
                Sum = Sum + (metallSystemElement.PortialPercent / metallElement.Mass);
            }

            foreach (MetallSystemElement item in metallcollection)
            {
                item.N = item.PortialPercent / (item.Mass * Sum);
            }

        }

        #endregion

        public void CalcMetallSystemProperties()
        {
            double[,] desh = new double[metallcollection.Count, metallcollection.Count];
            double[,] deshsh = new double[metallcollection.Count, metallcollection.Count];
            double a1 = default(double);
            double a2 = default(double);
            RootBranch(ref a1, ref a2, ref desh, ref deshsh);
            double a = RootSolution(ref a1, ref a2, ref desh, ref deshsh); 
                  
            Coupla tmp = Coupla.Create("d", a);
            metallProperties = new List<Coupla>();
            metallProperties.Add(tmp);

            double SS1 = 0;
            foreach (var item in metallcollection)
            {
                SS1 = SS1 + ((Math.Log10(item.Ru0) - Math.Log10(a / 2)) / item.TgAlfa) * Math.Pow(item.N, 2);
            }

            double SS2 = 0;
            for (int i = 0; i < metallcollection.Count - 1; i++)
            {
                for (int j = i + 1; j < metallcollection.Count; j++)
                {
                    SS2 = SS2 + (metallcollection[i].N * metallcollection[j].N * desh[i, j]);
                }
            }
            double ZY = -2 * (SS1 + 2 * SS2);

            tmp = Coupla.Create("Zy", ZY);
            metallProperties.Add(tmp);
        }

        private void OtdKorde(double c00, double c11, double c22, double c33, double c44, ref double dee1, ref double dee2)
        {
            dee1 = 1;
            double Fsh1 = c00 - Math.Exp((c11 - c22 * dee1) * Math.Log(10, Math.E)) - Math.Exp((c33 - c44 * dee1) * Math.Log(10, Math.E));
            double h = 0.1;
            double Fsh2;
            do
            {
                dee2 = dee1 + h;
                Fsh2 = c00 - Math.Exp((c11 - c22 * dee2) * Math.Log(10, Math.E)) - Math.Exp((c33 - c44 * dee2) * Math.Log(10, Math.E));
                if (Fsh1 * Fsh2 > 0)
                {
                    if (Math.Abs(Fsh2) > Math.Abs(Fsh1))
                    {
                        h = -h;
                    }
                    else
                    {
                        dee1 = dee2;
                        Fsh1 = Fsh2;
                        h = 2 * h;
                    }
                }

            } while (Fsh1 * Fsh2 > 0);
        }

        private void Korende(double c00, double c11, double c22, double c33, double c44, double dee1, double dee2, ref double ddee)
        {
            double eps1 = 0.000001;
            double eps2 = 0.000001;
            double Fsh1 = c00 - Math.Exp((c11 - c22 * dee1) * Math.Log(10, Math.E)) - Math.Exp((c33 - c44 * dee1) * Math.Log(10, Math.E));
            double Fsh2 = c00 - Math.Exp((c11 - c22 * dee2) * Math.Log(10, Math.E)) - Math.Exp((c33 - c44 * dee2) * Math.Log(10, Math.E));
            if (Fsh1 < 0) { ddee = dee1; }
            if (Fsh2 < 0) { ddee = dee2; }
            double dee;
            double Fsh;
            do
            {
                dee = ddee;
                Fsh = c00 - Math.Exp((c11 - c22 * dee) * Math.Log(10, Math.E)) - Math.Exp((c33 - c44 * dee) * Math.Log(10, Math.E));
                double Fshch = c22 * Math.Log(10, Math.E) * Math.Exp((c11 - c22 * dee) * Math.Log(10, Math.E)) + c44 * Math.Log(10, Math.E) * Math.Exp((c33 - c44 * dee) * Math.Log(10, Math.E));
                ddee = dee - (Fsh / Fshch);
                Fsh = c00 - Math.Exp((c11 - c22 * ddee) * Math.Log(10, Math.E)) - Math.Exp((c33 - c44 * ddee) * Math.Log(10, Math.E));

            } while ((Math.Abs(ddee - dee) > eps2) && ((Math.Abs(Fsh)) > eps1));
        }

        private void deltae(double a, ref double[,] desh, ref double[,] deshsh)
        {
            double[,] Zmin = new double[metallcollection.Count, metallcollection.Count];
            double[,] c0 = new double[metallcollection.Count, metallcollection.Count];
            double[,] c1 = new double[metallcollection.Count, metallcollection.Count];
            double[,] c2 = new double[metallcollection.Count, metallcollection.Count];
            double[,] c3 = new double[metallcollection.Count, metallcollection.Count];
            double[,] c4 = new double[metallcollection.Count, metallcollection.Count];

            for (int u = 0; u < 2; u++)
            {
                for (int i = 0; i < metallcollection.Count - 1; i++)
                {
                    for (int j = i + 1; j < metallcollection.Count; j++)
                    {
                        Zmin[i, j] = Math.Log10((metallcollection[i].Ru0 * metallcollection[i].TgAlfa) / (metallcollection[j].Ru0 * metallcollection[j].TgAlfa)) / (metallcollection[i].TgAlfa + metallcollection[j].TgAlfa);
                        if (u == 0)
                        {
                            c0[i, j] = a;
                        }
                        else
                        {
                            c0[i, j] = 0.866 * a;
                        }
                        c1[i, j] = Math.Log10(metallcollection[i].Ru0) - (metallcollection[i].TgAlfa * Zmin[i, j]);
                        c2[i, j] = (metallcollection[i].TgAlfa * metallcollection[j].TgAlfa) / (metallcollection[i].TgAlfa + metallcollection[j].TgAlfa);
                        c3[i, j] = Math.Log10(metallcollection[j].Ru0) + (metallcollection[j].TgAlfa * Zmin[i, j]);
                        c4[i, j] = (metallcollection[i].TgAlfa * metallcollection[j].TgAlfa) / (metallcollection[i].TgAlfa + metallcollection[j].TgAlfa);
                        double dee1 = new double();
                        double dee2 = new double();
                        OtdKorde(c0[i, j], c1[i, j], c2[i, j], c3[i, j], c4[i, j], ref dee1, ref dee2);
                        double ddee = new double();
                        Korende(c0[i, j], c1[i, j], c2[i, j], c3[i, j], c4[i, j], dee1, dee2, ref ddee);
                        if (u == 0)
                        {
                            desh[i, j] = ddee;
                        }
                        else
                        {
                            deshsh[i, j] = ddee;
                        }
                    }
                }

            }
        }

        private double F(double a, double[,] desh, double[,] deshsh)
        {
            double S1 = 0;
            double S2 = 0;
            double S3 = 0;
            double S4 = 0;
            foreach (MetallSystemElement item in metallcollection)
            {
                S1 = S1 + ((Math.Log10(item.Ru0) - Math.Log10(a / 2)) / item.TgAlfa) * Math.Pow(item.N, 2);
                S2 = S2 + ((Math.Log10(item.Ru0) - Math.Log10((0.866 * a) / 2)) / item.TgAlfa) * Math.Pow(item.N, 2);
            }
            for (int i = 0; i < metallcollection.Count - 1; i++)
            {
                for (int j = i + 1; j < metallcollection.Count; j++)
                {
                    S3 = S3 + metallcollection[i].N * metallcollection[j].N * desh[i, j];
                    S4 = S4 + metallcollection[i].N * metallcollection[j].N * deshsh[i, j];
                }

            }
            return 2 * (S1 + 2 * S3) + 8 * (S2 + 2 * S4);
        }

        private void RootBranch(ref double a1, ref double a2, ref double[,] desh, ref double[,] deshsh)
        {
            a1 = 2.5;
            deltae(a1, ref desh, ref deshsh);
            double F1 = F(a1, desh, deshsh);
            double h = 0.1;
            double F2 = default(double);
            do
            {
                a2 = a1 + h;
                deltae(a2, ref desh, ref deshsh);
                F2 = F(a2, desh, deshsh);
                if (F1 * F2 > 0)
                {
                    if (Math.Abs(F2) > Math.Abs(F1))
                    {
                        h = -h;
                    }
                    else
                    {
                        a1 = a2;
                        F1 = F2;
                        h = 2 * h;

                    }
                }


            } while (F1 * F2 > 0);
        }

        private double RootSolution(ref double a1, ref double a2, ref double[,] desh, ref double[,] deshsh)
        {
            double eps1 = 0.000001;
            double eps2 = 0.000001;
            deltae(a1, ref desh, ref deshsh);
            double F1 = F(a1, desh, deshsh);
            deltae(a2, ref desh, ref deshsh);
            double F2 = F(a2, desh, deshsh);
            double sch = default(double);
            double a3 = default(double);
            if (F1 > 0)
            {
                do
                {
                    a3 = a2 - ((F2 * (a1 - a2)) / (F1 - F2));
                    deltae(a3, ref desh, ref deshsh);
                    double F3 = F(a3, desh, deshsh);
                    if ((Math.Abs(a3 - a2) < eps1) && (Math.Abs(F3) < eps2))
                    {
                        sch = 1;
                    }
                    else
                    {
                        sch = 0;
                        a2 = a3;
                        F2 = F3;
                    }
                } while (sch != 1);
            }
            else
            {
                do
                {
                    a3 = a1 - ((F1 * (a2 - a1)) / (F2 - F1));
                    deltae(a3, ref desh, ref deshsh);
                    double F3 = F(a3, desh, deshsh);
                    if ((Math.Abs(a3 - a1) < eps1) && (Math.Abs(F3) < eps2))
                    {
                        sch = 1;
                    }
                    else
                    {
                        sch = 0;
                        a1 = a3;
                        F1 = F3;
                    }
                } while (sch != 1);
            }
            return a3;
        }

        #region Properties

        /// <summary>
        /// Properties of metall system
        /// </summary>
        public List<Coupla> metallProperties { get; set; }

        /// <summary>
        /// 
        /// </summary>
        private List<MetallSystemElement> metallcollection { get; set; }

        #endregion

    }
}
